﻿using System;
using System.Collections.Generic;
using System.Xml;
using CodePlex.TeamFoundation.Adapters;
using CodePlex.TeamFoundation.Adapters.WorkItemTracking;
using Microsoft.TeamFoundation.Build.Client;

namespace CodePlex.TeamFoundation.Utilities
{
  public class BuildUtilities
  {
    /// <summary>
    /// This method updates the state of the associated work items for a BuildCompletionEvent
    /// </summary>
    /// <param name="tfsFactory">Used to access TFS API objects</param>
    /// <param name="eventXml">the eventXml from a BuildCompletionEvent</param>
    /// <param name="transitionFromState">Update all associated work items currently in this state. If this paramter is empty, then update all associated work items</param>
    /// <param name="transitionToState">Change the matching work items to this state.</param>
    public void UpdateWorkItemsForBuild(
      ITfsFactory tfsFactory, 
      string eventXml, 
      string transitionFromState, 
      string transitionToState)
    {
      System.Uri buildUri = GetBuildUri(eventXml);
      IBuildDetail buildDetail = tfsFactory.GetBuildServer().GetAllBuildDetails(buildUri);
      List<IWorkItemSummary> workItemSummaryList = tfsFactory.GetAssociatedWorkItems(buildDetail);
      foreach (IWorkItemSummary workItemSummary in workItemSummaryList)
      {
        UpdateWorkItem(
          tfsFactory, 
          buildDetail.BuildNumber, 
          workItemSummary, 
          transitionFromState, 
          transitionToState);
      }
    }

    /// <summary>
    /// Derive the build URI from the BuildCompleteEvent eventXml
    /// This is kind of kludgy, but I cannot think of a better way to do it
    /// </summary>
    /// <param name="eventXml">the eventXml from a BuildCompletionEvent</param>
    /// <returns>The build URI</returns>
    private System.Uri GetBuildUri(string eventXml)
    {
      XmlDocument doc = new XmlDocument();
      doc.LoadXml(eventXml);
      XmlNode IdNode = doc.SelectSingleNode("//BuildCompletionEvent/Url");
      if (IdNode == null)
        throw new ApplicationException("BuildCompletionEvent Url not found");
      string buildUrl = IdNode.InnerText;
      string buildMoniker = buildUrl.Substring(buildUrl.IndexOf("=") + 1);
      string buildUri = "vstfs:///Build/Build/" + buildMoniker;
      return new System.Uri(buildUri);
    }

    /// <summary>
    /// Update a single work item associated with the build
    /// </summary>
    /// <param name="tfsFactory">Used to access TFS API objects</param>
    /// <param name="tfsBuildNumber">The build number</param>
    /// <param name="tfsWorkItemSummary">Summary information about an associated work item</param>
    /// <param name="transitionFromState">Update all associated work items currently in this state. If this paramter is empty, then update all associated work items</param>
    /// <param name="transitionToState">Change the matching work items to this state.</param>
    private void UpdateWorkItem(
      ITfsFactory tfsFactory, 
      string tfsBuildNumber, 
      IWorkItemSummary tfsWorkItemSummary, 
      string transitionFromState, 
      string transitionToState)
    {
      IWorkItem tfsWorkItem = tfsFactory.GetWorkItemStore().GetWorkItem(tfsWorkItemSummary.WorkItemId);
      // Only update the work Item if no conditional status was provided or if the conditional status matches
      if (transitionFromState == string.Empty || tfsWorkItem.State.ToLower().Trim() == transitionFromState.ToLower().Trim())
      {
        // Update the state and add a note in the history stating the build process made this change.
        tfsWorkItem.History = string.Format("Build {0} changed state from {1} to {2}", tfsBuildNumber, tfsWorkItem.State, transitionToState);
        tfsWorkItem.State = transitionToState;
        tfsWorkItem.Save();
      }
    }
  }
}
